package com.gillion.grule.client.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gillion.grule.client.SimilarityReckon.SimilarityReckon;
import com.gillion.grule.client.components.DubboComponent;
import com.gillion.grule.client.components.GroovyShellComponent;
import com.gillion.grule.client.components.JDBCComponent;
import com.gillion.grule.client.components.LocalServiceComponent;
import com.gillion.grule.client.components.RuleComponent;
import com.gillion.grule.client.components.SpringCloudComponent;
import com.gillion.grule.client.core.ComponentHolder;
import com.gillion.grule.client.core.Context;
import com.gillion.grule.client.core.HolidaysModel;
import com.gillion.grule.client.exception.ExecutorException;
import com.gillion.grule.client.validator.Validator;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;




import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.mvel2.MVEL;
import org.mvel2.PropertyAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class Tools {
    private static final Logger logger = LoggerFactory.getLogger(Tools.class);










   /* public static <T> T executeEsb(Context context, String serviceName, Object... object) {
        Map<String, Object> map = Maps.newConcurrentMap();
        List<Object> paramsMap = Lists.newArrayList();
        map.put("serviceName", serviceName);
        map.put("params", paramsMap);
        map.put("type", "edit");
        if (null == object) {
            paramsMap.add(null);
        } else {
            paramsMap.addAll(Arrays.asList(object));
        }
        RemoteServiceComponent remoteServiceComponent = (RemoteServiceComponent)ComponentHolder.getComponent("RemoteService");
        Object returnMes = remoteServiceComponent.execute(JSON.toJSONString(map), context);
        return (T)returnMes;
    }*/










    public static <T> T executeLocalService(Context context, String serviceName, Object... object) {
        Map<String, Object> map = Maps.newConcurrentMap();
        List<Object> paramsMap = Lists.newArrayList();
        map.put("localService", serviceName);
        map.put("params", paramsMap);
        map.put("type", "edit");
        if (null == object) {
            paramsMap.add(null);
        } else {
            paramsMap.addAll(Arrays.asList(object));
        }
        LocalServiceComponent localServiceComponent = (LocalServiceComponent)ComponentHolder.getComponent("LocalService");
        Object returnMes = localServiceComponent.execute(JSON.toJSONString(map), context);
        return (T)returnMes;
    }











    public static <T> T executeJDBC(Context context, Object sqlName, Object sqlColumn, Object... object) {
        logger.info("规则引擎 调用jdbc配置开始");
        System.out.println("规则引擎 调用jdbc配置开始");
        JDBCComponent jdbcComponent = new JDBCComponent();
        Map<Object, Object> map = new HashMap<>();
        List<Object> paramsMap = Lists.newArrayList();
        map.put("sqlName", sqlName);
        map.put("params", paramsMap);
        map.put("sqlColumn", sqlColumn);
        map.put("type", "edit");
        if (null == object) {
            paramsMap.add(null);
        } else {
            paramsMap.addAll(Arrays.asList(object));
        }
        return (T)jdbcComponent.execute(JSON.toJSONString(map), context);
    }










    public static <T> T executeDubbo(Context context, Object dubboName, Object... object) {
        DubboComponent dubboComponent = new DubboComponent();
        Map<String, Object> map = Maps.newConcurrentMap();
        List<Object> paramsMap = Lists.newArrayList();
        map.put("dubboName", dubboName);
        map.put("params", paramsMap);
        map.put("type", "edit");
        if (null == object) {
            paramsMap.add(null);
        } else {
            paramsMap.addAll(Arrays.asList(object));
        }
        return (T)dubboComponent.execute(JSON.toJSONString(map), context);
    }

    public static <T> T executeSpringCloud(Context context, String serviceName, Object... object) {
        Map<String, Object> map = Maps.newConcurrentMap();
        List<Object> paramsMap = Lists.newArrayList();
        map.put("springCloudName", serviceName);
        map.put("params", paramsMap);
        map.put("type", "edit");
        if (null == object) {
            paramsMap.add(null);
        } else {
            paramsMap.addAll(Arrays.asList(object));
        }
        SpringCloudComponent springCloudComponent = (SpringCloudComponent)ComponentHolder.getComponent("SpringCloudService");
        Object returnMes = springCloudComponent.execute(JSON.toJSONString(map), context);
        return (T)returnMes;
    }

    public static <T> T executeGroovyShell(Context context, String shellName, Object... object) {
        Map<String, Object> map = Maps.newConcurrentMap();
        List<Object> paramsMap = Lists.newArrayList();
        map.put("shellName", shellName);
        map.put("params", paramsMap);
        map.put("type", "edit");

        if (null == object) {
            paramsMap.add(null);
        } else {
            paramsMap.addAll(Arrays.asList(object));
        }
        GroovyShellComponent groovyShellComponent = (GroovyShellComponent)ComponentHolder.getComponent("GroovyShellService");
        Object returnMes = groovyShellComponent.execute(JSON.toJSONString(map), context);
        return (T)returnMes;
    }










    public static <T> T executeRule(String groupId, String artifactId, Object... args) {
        RuleComponent ruleComponent = (RuleComponent)ComponentHolder.getComponent("Rule");
        return (T)ruleComponent.execute(groupId, artifactId, args);
    }








    public static boolean startWith(String str, String code) {
        if (str != null) {
            return str.startsWith(code);
        }
        return false;
    }







    public static void throwException(Object message) {
        throw new ExecutorException(500000, message.toString());
    }








    public static boolean startWith(Object str, String code) {
        if (str != null) {
            String s = str.toString();
            return s.startsWith(code);
        }
        return false;
    }









    public static boolean endsWith(String str, String code) {
        if (str != null) {
            return str.endsWith(code);
        }
        return false;
    }









    public static boolean endsWith(Object str, String code) {
        if (str != null) {
            String s = str.toString();
            return s.endsWith(code);
        }
        return false;
    }









    public static boolean matchWith(String str, String code) {
        if (str != null) {
            return str.contains(code);
        }
        return false;
    }









    public static boolean matchWith(Object str, String code) {
        if (str != null) {
            String s = str.toString();
            return s.contains(code);
        }
        return false;
    }









    public static Object rate(Object rateList, Object objectValue) {
        return rate((List)rateList, objectValue);
    }









    public static Object rate(Object rateList, Object objectValue, Object countValue) {
        return rate((List)rateList, objectValue, countValue);
    }








    public static Object rate(List rateList, Object objectValue) {
        Double value = Double.valueOf(Double.parseDouble(objectValue.toString()));
        double count = 0.0D;
        for (Object object : rateList) {
            Map rateMap;
            if (object instanceof Map) {
                rateMap = (Map)object;
            } else {
                String rateString = JSON.toJSONString(object);
                rateMap = (Map)JSON.parseObject(rateString, Map.class);
            }
            Double min = Double.valueOf(Double.parseDouble(rateMap.get("intervalStart").toString()));
            Double max = Double.valueOf(Double.parseDouble(rateMap.get("intervalOver").toString()));
            Double rateValue = Double.valueOf(Double.parseDouble(rateMap.get("intervalValue").toString()));
            double type = Double.parseDouble((rateMap.get("type") == null) ? "1" : rateMap.get("type").toString());
            if (type == 0.0D) {
                if (value.doubleValue() > min.doubleValue() && value.doubleValue() <= max.doubleValue())
                    return rateValue;
                if (max.equals(min) && max.equals(value))
                    return rateValue;  continue;
            }
            if (type == 1.0D && value.doubleValue() > min.doubleValue() && value.doubleValue() <= max.doubleValue())
                return Double.valueOf(value.doubleValue() * rateValue.doubleValue());
            if (type == 2.0D) {
                if (min.doubleValue() > value.doubleValue())
                    return Double.valueOf(count);
                if (value.doubleValue() >= max.doubleValue()) {
                    count += (max.doubleValue() - min.doubleValue()) * rateValue.doubleValue(); continue;
                }
                count += (value.doubleValue() - min.doubleValue()) * rateValue.doubleValue();
            }
        }

        return Double.valueOf(count);
    }









    public static Object rate(List rateList, Object objectValue, Object countValue) {
        double value = Double.parseDouble(objectValue.toString());
        for (Object object : rateList) {
            Map rateMap;
            if (object instanceof Map) {
                rateMap = (Map)object;
            } else {
                String rateString = JSON.toJSONString(object);
                rateMap = (Map)JSON.parseObject(rateString, Map.class);
            }
            double min = Double.parseDouble(rateMap.get("intervalStart").toString());
            double max = Double.parseDouble(rateMap.get("intervalOver").toString());
            Double rateValue = Double.valueOf(Double.parseDouble(rateMap.get("intervalValue").toString()));
            Double count = Double.valueOf(Double.parseDouble(countValue.toString()));
            double type = Double.parseDouble((rateMap.get("type") == null) ? "1" : rateMap.get("type").toString());
            if (type == 1.0D && value > min && value <= max) {
                return Double.valueOf(count.doubleValue() * rateValue.doubleValue());
            }
        }
        return Integer.valueOf(0);
    }







    public static <T extends Comparable> T max(T... args) {
        List<T> list = Arrays.asList(args);
        Collections.sort(list);
        return list.get(list.size() - 1);
    }







    public static <T extends Comparable> T min(T... args) {
        List<T> list = Arrays.asList(args);
        Collections.sort(list);
        return list.get(0);
    }







    public static double avg(Object... args) {
        DecimalFormat df = new DecimalFormat("#.00");
        double count = 0.0D;
        for (Object obj : args) {
            count += Double.parseDouble(obj.toString());
        }
        return Double.parseDouble(df.format(count / args.length));
    }







    public static double sum(Object... args) {
        double count = 0.0D;
        for (Object obj : args) {
            count += Double.parseDouble(obj.toString());
        }
        return count;
    }








    public static void putMap(Object obj, String key, Object value) {
        Map<String, Object> map = (Map)obj;
        map.put(key, value);
    }








    public static Object getMap(Object obj, Object key) {
        Map map = (Map)obj;
        if (key instanceof String) {
            return map.get(key);
        }
        return map.get(key.toString());
    }







    public static void clearList(Object obj) {
        List list = (List)obj;
        list.clear();
    }






    public static void clearMap(Object obj) {
        Map map = (Map)obj;
        map.clear();
    }








    public static Object matcher(Object value, String expression) {
        Pattern pattern = Pattern.compile(expression);
        if (value != null) {
            return Boolean.valueOf(pattern.matcher(value.toString()).matches());
        }
        return Boolean.valueOf(false);
    }








    public static void listAdd(List<Object> list, Object obj) {
        list.add(obj);
    }







    public static void listAdd(Object list, Object obj) {
        ((List<Object>)list).add(obj);
    }




    /*public static void exception(Context context, Object map) {
        String accountObjectType, node;
        int expectedNodeOrActualNode;
        String accountObjectId;
        Map<String, Object> map1 = (Map)map;
        map1.put("exceptionInput", "no exceptionInput");
        map1.put("exceptionTime", new Date());
        map1.put("exceptionCode", "060101");




        try {
            accountObjectType = MVEL.eval("params[1].billType", context).toString();
        } catch (Exception pe) {
            logger.info("异常服务初始化异常", pe);
            accountObjectType = "-";
        }

        try {
            node = MVEL.eval("params[1].nodeCode", context).toString();
        } catch (PropertyAccessException|StringIndexOutOfBoundsException pe) {
            logger.info("异常服务初始化异常", pe);
            node = "-";
        } catch (Exception e) {
            logger.error("异常服务初始化异常", e);
            node = "-";
        }
        try {
            expectedNodeOrActualNode = Integer.parseInt(MVEL.eval("params[1].nodeType", context).toString());
        } catch (PropertyAccessException|StringIndexOutOfBoundsException pe) {
            logger.info("异常服务初始化异常", pe);
            expectedNodeOrActualNode = 0;
        } catch (Exception e) {
            logger.error("异常服务初始化异常", e);
            expectedNodeOrActualNode = 0;
        }
        try {
            accountObjectId = MVEL.eval("params[1].dcoId", context).toString();
        } catch (PropertyAccessException|StringIndexOutOfBoundsException pe) {
            logger.info("异常服务初始化异常", pe);
            accountObjectId = "-";
        } catch (Exception e) {
            logger.error("异常服务初始化异常", e);
            accountObjectId = "-";
        }
        map1.put("accountObjectType", accountObjectType);
        map1.put("node", node);
        map1.put("expectedNodeOrActualNode", Integer.valueOf(expectedNodeOrActualNode));
        map1.put("accountObjectId", accountObjectId);
        InParameterMustService inParameterMustService = ContextHolder.<InParameterMustService>getBean("inParameterMustService");
        ((InParameterMustService)Objects.<InParameterMustService>requireNonNull(inParameterMustService)).setMap(accountObjectType, map1, context);
        try {
            Class<?> clazz = Class.forName("com.gillion.bms.core.dto.FouExceptionInfoDTO");
            Class[] classArray = new Class[1];
            classArray[0] = clazz;

            Object client = ContextHolder.getBean("fouExceptionInfoServiceClient");
            Method method = Objects.<T>requireNonNull((T)client).getClass().getDeclaredMethod("saveAccountExceptionInfoSelective", classArray);

            logger.info("异常服务调用开始：" + map1);
            Object param = clazz.newInstance();
            Object obj = JSON.parseObject(JSON.toJSONString(map1), param.getClass());
            Object returnResult = method.invoke(client, new Object[] { obj });
            logger.info("异常服务调用结束" + JSON.toJSONString(returnResult));
        } catch (Exception e) {
            logger.error("价格服务异常：", e);
        }
    }*/







    public static int getListSize(Object object) {
        if (object == null) {
            return 0;
        }
        return ((List)object).size();
    }








    public static boolean checkList(Object obj, String key) {
        if (obj instanceof List) {
            List<Map> list = (List)obj;
            for (int i = 0; i < list.size(); i++) {
                Map map = list.get(i);
                for (int j = 0; j < list.size(); j++) {
                    Map jmap = list.get(j);
                    if (jmap.get(key).equals(map.get(key)) && j != i) {
                        return true;
                    }
                }
            }
        }
        return false;
    }







    public static Integer StringLength(Object object) {
        if (null == object) {
            return Integer.valueOf(0);
        }
        return Integer.valueOf(object.toString().length());
    }







    public static Integer StringLength(String object) {
        if (null == object) {
            return Integer.valueOf(0);
        }
        return Integer.valueOf(object.length());
    }








    public static boolean isHolidays(Object obj) {
        if (obj instanceof String) {
            for (HolidaysModel holidaysModel : Holidays.holidays) {
                if (obj.equals(holidaysModel.getHoliday())) {
                    if (holidaysModel.getType().intValue() == 0)
                        return true;
                    if (holidaysModel.getType().intValue() == 1) {
                        return false;
                    }
                }
            }
            String str = obj.toString().substring(0, 8);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

            try {
                Date date = sdf.parse(str);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(date);
                int i = calendar.get(7);
                if (i == 7 || i == 1) {
                    return true;
                }
            } catch (Exception e) {
                logger.error("工作日计算失败！", e);
            }
        }
        return false;
    }








    public static Object rounding(Object value, Object figure) {
        StringBuilder val = new StringBuilder("#.");
        for (int i = 0; i < Integer.parseInt(figure.toString()); i++) {
            val.append("0");
        }
        return new BigDecimal((new DecimalFormat(val.toString())).format(value));
    }







    public static Object roundUp(Object value) {
        return Double.valueOf(Math.ceil(Double.parseDouble(value.toString())));
    }








    public static Object roundUpPointHalf(Object value) {
        String val = (new DecimalFormat("#.##")).format(Double.parseDouble(value.toString()));
        BigDecimal[] remainder = (new BigDecimal(val)).divideAndRemainder(BigDecimal.ONE);
        int compareResult = remainder[1].compareTo(BigDecimal.valueOf(0.5D));
        if (compareResult > 0) {
            return remainder[0].add(BigDecimal.valueOf(1L));
        }
        return remainder[0].add(BigDecimal.valueOf(0.5D));
    }








 /*   public static String convertToSimple(Object mes) {
        if (mes instanceof Map) {
            Map<String,Object> map = (Map)mes;
            for (String key : map.keySet()) {
                if (map.get(key) instanceof String) {
                    map.put(key, ZhConverterUtil.convertToSimple(map.get(key)+""));
                }
            }
            return null;
        }
        if (mes instanceof String) {
            return ZhConverterUtil.convertToSimple(mes.toString());
        }
        return null;
    }*/







    public static void trim(Map map) {

        for (Object key : map.keySet()) {
            if (map.get(key) instanceof String) {
                map.put(key, map.get(key).toString().trim());
            }
        }

    }









    public static void trim(Object obj, String key) {
        if (obj instanceof Map) {
            Map map = (Map)obj;
            map.get(key);
        }
    }









    public static boolean validatorData(Context context, String key, Object value) {
        Validator validator = new Validator();
        if (value instanceof Map) {
            return validator.validate((Map)value, (Map)context.getValidatorConfig().get(key));
        }
        return validator.validate((List)value, (Map)context.getValidatorConfig().get(key));
    }










    public static List similarityReckon(String keysStr, JSONArray listObj, JSONArray listAll) {
        listAll.addAll((Collection)listObj);
        return SimilarityReckon.queryDocList(keysStr, listObj, listAll);
    }










    public static void listReplace(JSONArray list, String mapOldKey, String mapNewKey, String key, String value) {
        for (Object obj : list) {
            ((Map<String, String>)obj).put(mapNewKey, replace(((Map)obj).get(mapOldKey).toString(), key, value));
        }
    }










    public static String replace(String str, String key, String value) {
        String result = str;

        if (key.startsWith("(") && key.endsWith(")") && key.indexOf("|") > 0) {
            String simpleStr = key.substring(1, key.length() - 1);
            String[] sstr = simpleStr.split("\\|");
            for (String rkey : sstr) {
                result = result.replace(rkey, value);
            }
        } else {
            result = str.replace(key, value);
        }
        return result;
    }







    public static String upperCase(String str) {
        return str.toUpperCase();
    }









    public static String subStr(String str, Integer start, Integer end) {
        return str.substring(start.intValue(), end.intValue());
    }








    public static Integer indexOf(String str, String value) {
        return Integer.valueOf(str.indexOf(value));
    }







    public static String parseString(JSONObject obj) {
        String result = "";
        if (obj == null) {
            return "";
        }
        try {
            result = JSON.toJSONString(obj);
        } catch (Exception e) {
            logger.error("对象转字符串出错！", e);
        }
        return result;
    }






    public static String getUUid() {
        return UUID.randomUUID().toString();
    }











    public static BigDecimal handlingCharges(Object count, Object countSign, Object price1, Object price2) {
        BigDecimal bCount = new BigDecimal(count.toString());
        BigDecimal bCountSign = new BigDecimal(countSign.toString());
        BigDecimal bPrice1 = new BigDecimal(price1.toString());
        BigDecimal bPrice2 = new BigDecimal(price2.toString());


        int groupCount = bCount.divide(bCountSign).intValue();
        BigDecimal singleCount = bCount.divideAndRemainder(bCountSign)[1];
        BigDecimal groupPrice = bPrice1.multiply(new BigDecimal(groupCount));
        BigDecimal singlePrice = bPrice2.multiply(singleCount);
        return groupPrice.add(singlePrice);
    }








    public static Long compareHours(Date source1, Date source2) {
        long hours = 0L;
        try {
            long diff = source1.getTime() - source2.getTime();
            hours = diff / 3600000L;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Long.valueOf(hours);
    }







    public static Integer countLines(String source) {
        if (StringUtils.isEmpty(source)) {
            return Integer.valueOf(0);
        }
        return Integer.valueOf(StringUtils.countMatches(source, "\n") + StringUtils.countMatches(source, "\r\n"));
    }








    public static boolean validateLinesLength(String source, Integer maxLength) {
        String[] lines = StringUtils.split(source, "\n\r\n");
        for (String line : lines) {
            if (StringUtils.length(line) > maxLength.intValue()) {
                return false;
            }
        }
        return true;
    }
}


